(function() {

  // TD Storage
  var TodoStorage = new Backbone.LocalStorage('todos-backbone');

  // TD Model
  var Todo = Backbone.Model.extend({

    defaults: function() {
      return {
        title: 'empty todo...',
        order: todos.nextOrder(),
        done: false
      };
    },

    toggle: function() {
      this.save({done: !this.get('done')});
    }

  });

  // TD Collection
  var Todos = Backbone.Collection.extend({

    model: Todo,

    comparator: 'order',

    localStorage: TodoStorage,

    done: function() {
      return this.where({done: true});
    },

    remaining: function() {
      return this.where({done: false});
    },

    nextOrder: function() {
      if (!this.length) return 1;
      return this.last().get('order') + 1;
    }

  });

  var todos = new Todos;

  // TD View
  var TodoView = Backbone.View.extend({

    tagName: 'li',

    template: _.template([
      '<div class="view">',
      '<input class="toggle" type="checkbox" id="<%- id %>" <%= done ? "checked" : "" %> />',
      '<label for="<%- id %>"><%- title %></label>',
      '<a class="destroy"></a>',
      '</div>',
      '<input class="edit" type="text" value="<%- title %>" />'
    ].join('\n')),

    events: {
      'click .toggle': 'toggle',
      'dblclick .view': 'edit',
      'click a.destroy': 'destroy',
      'keypress .edit': 'keypress',
      'blur .edit': 'close'
    },

    initialize: function() {
      this.listenTo(this.model, 'change', this.render);
      this.listenTo(this.model, 'destroy', this.remove);
    },

    render: function() {
      this.$el.html(this.template(_.extend(this.model.toJSON(), {id: this.model.cid})));
      this.$el.toggleClass('done', this.model.get('done'));
      this.$input = this.$('.edit');
      return this;
    },

    toggle: function() {
      this.model.toggle();
    },

    edit: function() {
      this.$el.addClass('editing');
      this.$input.focus();
    },

    close: function() {
      var value = this.$input.val();
      if (!value) {
        this.destroy();
      } else {
        this.model.save({title: value});
        this.$el.removeClass('editing');
      }
    },

    keypress: function(e) {
      if (e.keyCode === 13) this.close();
    },

    destroy: function() {
      this.model.destroy();
    }

  });

  // TDs View
  var TodosView = Backbone.View.extend({

    el: document.querySelector('#todo-list'),

    initialize: function() {
      this.listenTo(todos, 'add', this.append);
    },

    append: function(todo) {
      var view = new TodoView({model: todo});
      todo.view = view;
      this.$el.append(view.render().el);
    }

  });

  // App View
  var AppView = Backbone.View.extend({

    el: document.querySelector('#todoapp'),

    footerTemplate: _.template([
      '<% if (done) { %>',
      '<a id="clear-completed">Clear <%= done %> completed <%= done > 1 ? "items" : "item" %></a>',
      '<% } %>',
      '<div class="todo-count"><b><%= remaining %></b> <%= remaining > 1 ? "items" : "item" %> left</div>'
    ].join('\n')),

    events: {
      'keypress #new-todo': 'keypress',
      'click #clear-completed': 'clearCompleted',
      'click #toggle-all': 'toggleAllComplete'
    },

    initialize: function() {

      this.listenTo(todos, 'all', this.render);

      this.$input = this.$('#new-todo');
      this.allCheckbox = this.$('#toggle-all').get(0);
      this.$footer = this.$('footer');
      this.$main = this.$('#main');

      this.todosView = new TodosView;

      this.last_done = 0;
      this.last_remaining = 0;

      todos.fetch();
    },

    render: function(e) {
      // console.log('render', e);
      var done = todos.done().length;
      var remaining = todos.remaining().length;
      if (done === this.last_done && remaining === this.last_remaining) {
        return;
      } else {
        this.last_done = done;
        this.last_remaining = remaining;
      }
      // console.log('bingo');
      if (todos.length) {
        this.$main.removeClass('hide');
        this.$footer.removeClass('hide');
        this.$footer.html(this.footerTemplate({done: done, remaining: remaining}));
      } else {
        this.$main.addClass('hide');
        this.$footer.addClass('hide');
      }

      this.allCheckbox.checked = !remaining;
    },

    keypress: function(e) {
      if (!this.$input.val()) return;
      if (e.keyCode === 13) {
        var todo = new Todo({title: this.$input.val()});
        todos.add(todo);
        todo.save();
        this.$input.val('');
      }
    },

    clearCompleted: function() {
      _.invoke(todos.done(), 'destroy');
      return false;
    },

    toggleAllComplete: function() {
      var done = this.allCheckbox.checked;
      todos.each(function(todo) {
        todo.save({'done': done});
      });
    }

  });

  var appView = new AppView;

  // For Easily Debuging
  window.todos = todos;
  window.appView = appView;

})();
